
#include "kraw/runtime.h"
#include "kraw/kraw3d.h"

#include "kernel/nkernelserver.h"
#include "kernel/ntimeserver.h"
#include "kernel/nfileserver2.h"
#include "kernel/nscriptserver.h"
#include "resource/nresourceserver.h"
#include "variable/nvariableserver.h"
#include "anim2/nanimationserver.h"
#include "particle/nparticleserver.h"
#include "misc/ncaptureserver.h"
#include "misc/nprefserver.h"
#include "misc/nconserver.h"

nNebulaUsePackage(nnebula);
nNebulaUsePackage(nscene);
nNebulaUsePackage(nlua);
nNebulaUsePackage(krayserkraw);

extern int KrawMain( Runtime& runtime );

//------------------------------------------------------------------------------

//#ifdef __WIN32__
//int WINAPI
//WinMain( HINSTANCE /*hInstance*/, HINSTANCE /*prevInstance*/, LPSTR lpCmdLine, int /*nCmdShow*/ )
//{
//    nWinMainCmdLineArgs args( lpCmdLine );
//#else
int
main( int argc, const char** argv )
{
    nCmdLineArgs args( argc, argv );
//#endif

    nKernelServer kernel;

    #ifdef __WIN32__
        nWin32LogHandler logHandler( "krayserkraw" );
        kernel.SetLogHandler( &logHandler );
    #endif
    kernel.AddPackage(nnebula);
    kernel.AddPackage(nscene);
    kernel.AddPackage(nlua);
    kernel.AddPackage(krayserkraw);

    //init nebula runtime
    Runtime runtime;
    runtime.SetArgs(args);
    runtime.Init();

    int result = KrawMain( runtime );

    //shutdown nebula runtime
    runtime.Shutdown();

    return result;
}

//------------------------------------------------------------------------------

Runtime::Runtime() :
    prevTime(0.0),
    frameId(0)
{
    //
}

//------------------------------------------------------------------------------

void Runtime::Init()
{
    // initialize Nebula runtime
    nKernelServer* kernel( nKernelServer::Instance() );

    const char *gfxClass = this->args.GetStringArg( "-gfxclass", "krawd3d9" );//"krawd3d10", "krawgl2", etc.
    const char *scriptClass = this->args.GetStringArg( "-scriptclass", "nluaserver" );

    //allow customizing the classes of servers: graphics, etc.
/*    this->refScriptServer   = (nScriptServer*)    kernel->New(this->GetScriptServerClass().Get(), "/sys/servers/script");
    this->refGfxServer      = (nGfxServer2*)      kernel->New(this->GetGfxServerClass().Get(), "/sys/servers/gfx");
    this->refInputServer    = (nInputServer*)     kernel->New("ndi8server", "/sys/servers/input");*/
    this->refScriptServer   = (nScriptServer*)    kernel->New( scriptClass, "/sys/servers/script" );
    this->refGfxServer      = (Kraw3D*)           kernel->New( gfxClass, "/sys/servers/gfx" );

    this->refConServer      = (nConServer*)       kernel->New("nconserver", "/sys/servers/console");
    this->refResourceServer = (nResourceServer*)  kernel->New("nresourceserver", "/sys/servers/resource");
    this->refVarServer      = (nVariableServer*)  kernel->New("nvariableserver", "/sys/servers/variable");
    this->refAnimServer     = (nAnimationServer*) kernel->New("nanimationserver", "/sys/servers/anim");
    this->refParticleServer = (nParticleServer*)  kernel->New("nparticleserver", "/sys/servers/particle");
    this->refPrefServer     = (nPrefServer*)      kernel->New("nwin32prefserver", "/sys/servers/pref");
    this->refCaptureServer  = (nCaptureServer*)   kernel->New("ncaptureserver", "/sys/servers/capture");

    this->refGfxServer->Init();

    const char* projDir = this->args.GetStringArg( "-proj", 0 );
    kernel->GetFileServer()->SetAssign( "proj", projDir ? projDir : kernel->GetFileServer()->GetAssign( "home" ) );

    const char* startup = this->args.GetStringArg( "-startup", "home:data/scripts/startup.lua" );
    if ( startup )
    {
        nString result;
        this->refScriptServer->RunScript( startup, result );
    }
}

//------------------------------------------------------------------------------

void Runtime::Shutdown()
{
    this->refGfxServer->Shutdown();

    //shutdown nebula2 runtime
    this->refConServer->Release();
    this->refResourceServer->Release();
    this->refVarServer->Release();
    this->refAnimServer->Release();
    this->refParticleServer->Release();
    this->refPrefServer->Release();
    this->refCaptureServer->Release();
}

//------------------------------------------------------------------------------

bool Runtime::Trigger()
{
    if ( !this->refGfxServer->Trigger() ) return false;

    //tick all nebula systems
    nTimeServer::Instance()->Trigger();

    nTime time = nTimeServer::Instance()->GetTime();
    if ( this->prevTime == 0.0 ) prevTime = time;

    //if ( !script->Trigger() ) return false;

    //input->Trigger( time );

    return true;
}

//------------------------------------------------------------------------------

void Runtime::Render()
{
    //traverse display lists
}
